package com.vvvtimes.demo.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.vvvtimes.demo.util.endecrypt.BcAesUtil;
import com.vvvtimes.demo.util.endecrypt.BcBfUtil;

import java.io.UnsupportedEncodingException;

public class NavicatePasswordUtil {
    private  Integer version = 0;
    private String  aesKey = "libcckeylibcckey";
    private  String aesIv = "libcciv libcciv ";
    private String blowString = "3DC5CA39";
    private byte[] blowKey = null;
    private  byte[]  blowIv = null;

    public NavicatePasswordUtil(Integer version) {
        this.version= version;
        this.blowKey= DigestUtil.sha1("3DC5CA39");
        this.blowIv = HexUtil.decodeHex("d9c7c3c8870d64bd");
    }

    public byte[]  decrypt(String s) {
        byte[]  result = new byte[0];

        switch (version) {
            case 11:
                result = decryptEleven(s);
                break;
            case 12:
                result =decryptTwelve(s);
                break;
            default:
                break;
        }
        return result;
    }

    private byte[] decryptTwelve(String upperString){
        byte[] string = HexUtil.decodeHex(upperString.toLowerCase());
        byte[] decrypt = null;
        try {
            decrypt = BcAesUtil.decrypt(string, this.aesKey.getBytes("utf-8"), this.aesIv.getBytes("utf-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
       return decrypt;
    }

    private  byte[]  decryptEleven(String upperString) {
       byte[] string = HexUtil.decodeHex(upperString.toLowerCase());

        int round = string.length / 8;

        int leftLength = string.length  % 8;
        byte[] result =new byte[0];
        byte[] currentVector = this.blowIv;
        for (int i = 0; i < round; i++) {
            byte[] encryptedBlock =new byte[8];
            ArrayUtil.copy(string,8*i,encryptedBlock,0,8);
            byte[] temp = XOR(decryptBlock(encryptedBlock), currentVector);
            currentVector = XOR(currentVector, encryptedBlock);
            result = ArrayUtil.addAll(result,temp);
        }
        if (leftLength>0) {
            System.out.println(Convert.toHex(currentVector) );
            currentVector = decryptBlock(currentVector);
            System.out.println(Convert.toHex(currentVector) );

            byte[] restBlock =new byte[leftLength];
            ArrayUtil.copy(string,8*round,restBlock,0,leftLength);
            byte[] temp = XOR(restBlock, currentVector);
            result = ArrayUtil.addAll(result,temp);
        }
        return result;
    }

    private byte[] decryptBlock(byte[] encryptedBlock) {
        //TODO 目前这个实现存在问题
        byte[] decrypt = BcBfUtil.decrypt(encryptedBlock, this.blowKey);
        return decrypt;
    }

    public byte[] XOR(byte[] A, byte[] B) {
        int n=A.length;
        int m=B.length;
        int k=0;
        if (n>m){
            k=n;
            byte[] result=new byte[k];
            for(int i=0;i<m;i++) {
                result[i]=(byte) (A[i]^B[i]);
            }
            for (int i=m-1;i<k;i++){
                result[i]=A[i];
            }
            return result;
        }
        else {
            k=m;
            byte[] result=new byte[k];
            for(int i=0;i<n;i++) {
                result[i]=(byte) (A[i]^B[i]);
            }
            for (int i=n-1;i<k;i++){
                result[i]=B[i];
            }
            return result;
        }
    }

    public static void main(String[] args) throws UnsupportedEncodingException {
        //11版本暂不好用
        NavicatePasswordUtil navicatePasswordUtil = new NavicatePasswordUtil(11);
        byte[] decode = navicatePasswordUtil.decrypt("15057D7BA390");
        if(decode !=null && decode.length>0){
            String s = new String(decode, "utf-8");
            System.out.println(s);
        }
    }


}
